#include <limits.h>
#include <sys/stat.h>
#include <string.h>

#include "sock.h"
#include "cconf.h"

#include <unistd.h>

#include <assert.h>
#include <zmq.h>

#define ENVDEF(s) getenv(#s)

struct cconf_sock_s {
	void * context;
	void * sock;
};

cconf_sock_t * cconf_sock_create(char * name, int server_client)
{
	char sock_path[PATH_MAX];
	char zmq_sock_name[PATH_MAX];
	int rc;
	cconf_sock_t * s = calloc(1, sizeof(cconf_sock_t));
	if (!s) return NULL;
	
	char * sock_root = ENVDEF(CCONF_SOCKET_PATH);
	if (sock_root == NULL)
		sock_root = CCONF_SOCKET_PATH;
		
	snprintf(sock_path, PATH_MAX-1, "%s/%s", sock_root, name);
	snprintf(zmq_sock_name, PATH_MAX-1, "ipc://%s/%s", sock_root, name);
	
	s->context = zmq_ctx_new();
	
	if (server_client)
	{
		//unlink(sock_path);
		s->sock = zmq_socket(s->context, ZMQ_REP);
		rc = zmq_bind (s->sock, zmq_sock_name);
	}
	else 
	{
		int timeo_ms = 10000;
		s->sock = zmq_socket(s->context, ZMQ_REQ);
		zmq_setsockopt(s->sock, ZMQ_RCVTIMEO, &timeo_ms, sizeof(timeo_ms));
		zmq_setsockopt(s->sock, ZMQ_SNDTIMEO, &timeo_ms, sizeof(timeo_ms));
		timeo_ms = 0;
		zmq_setsockopt(s->sock, ZMQ_LINGER, &timeo_ms, sizeof(timeo_ms));

		rc = zmq_connect (s->sock, zmq_sock_name);
	}
	
	if (rc != 0)
	{
		fprintf(stderr, "error creating socket at %s: %s\n", sock_path, strerror(errno));
	}
	
	assert(rc == 0);
	
	return s;
}


void cconf_sock_destroy(cconf_sock_t * sock)
{
	zmq_close(sock->sock);
	zmq_ctx_destroy(sock->context);
	
	free(sock);
}

static int cconf_sock_send_string_(cconf_sock_t * sock, char * str, int flags)
{
	zmq_msg_t message;
    zmq_msg_init_size (&message, strlen (str));
    memcpy (zmq_msg_data (&message), str, strlen (str));
    int size = zmq_msg_send (&message, sock->sock, flags);
    zmq_msg_close (&message);
    return (size);
}

int cconf_sock_send_string(cconf_sock_t * sock, char * str)
{
	return cconf_sock_send_string_(sock, str, 0);
}

int cconf_sock_send_string_nb(cconf_sock_t * sock, char * str)
{
	return cconf_sock_send_string_(sock, str, ZMQ_NOBLOCK);
}

char * cconf_sock_get_string(cconf_sock_t * sock)
{
	zmq_msg_t message;
    zmq_msg_init (&message);
    int size = zmq_msg_recv (&message, sock->sock, 0);
    if (size == -1)
        return NULL;
    char *string = malloc (size + 1);
    memcpy (string, zmq_msg_data (&message), size);
    zmq_msg_close (&message);
    string [size] = 0;
    return (string);
}
